#pragma once
#include <iostream>
#include <sys/epoll.h>
#include <memory>
#include "Socket.hpp"
#include "Epoll.hpp"

class EpollServer
{
    static const int num = 128;
private:
    uint16_t _port;
    std::shared_ptr<Socket> _plistensock;
    std::shared_ptr<Epoll> _pepoller;

    //禁止拷贝
    EpollServer(const EpollServer&)=delete;
    EpollServer& operator=(const EpollServer&)=delete;
public:
    EpollServer(uint16_t port = 8080)
        :_port(port)
        ,_plistensock(new Socket())
        ,_pepoller(new Epoll())
    {}


    ~EpollServer()
    {
        _plistensock->Close();
    }
    
public:
    void Init();
    void Start();
    void SendEvent(struct epoll_event revs[], int num);
    void NewLink();
    void ParseData(int fd);

};

//////////////////////////////////////////////////////////////////////////////////////////////////
void EpollServer::Init()
{
    _plistensock->Create();
    _plistensock->Bind(_port);
    _plistensock->Listen();

    cout << "create listensock success: " << _plistensock->GetSockfd()<< endl;
}

void EpollServer::Start()
{
    //将listensock添加到epoll中
    _pepoller->EpollCtl(EPOLL_CTL_ADD, _plistensock->GetSockfd(), EPOLLIN);
    struct epoll_event revs[num]; 
    while(1)
    {   
        //epoll会返回就绪事件的个数, 并写进epoll_event数组中-->到时候遍历这个数组查看
        int n = _pepoller->EpollWait(revs, num);
        if(n > 0)
        {
            //事件就绪
            cout << "event happend fd is " << revs[0].data.fd << endl;
            SendEvent(revs, n);

        }
        else if(n == 0)
        {
            //超时
            cout << "time out "<< endl;
        }
        else
        {
            //出错
            cout << "epoll wait error"<< endl;
        }
    }
}

//派发事件
void EpollServer::SendEvent(struct epoll_event revs[], int n)
{
    for(int i = 0; i < n; i++)
    {
        uint32_t events = revs[i].events;
        int fd = revs[i].data.fd;
        if(events & EPOLLIN)
        {
            //是新连接 
            if(fd == _plistensock->GetSockfd())
            {
                NewLink();
            }
            else
            {
                //资源就绪了
                cout << "ParseData" << endl;
                cout << fd << endl;
                ParseData(fd);
            }
        }
        //也可以是其它事件....可补充
    }
}

void EpollServer::NewLink()
{
    std::string client_ip;
    uint16_t client_port;
    int newsocket = _plistensock->Accept(&client_ip, &client_port);
    if(newsocket > 0)
    {
        //将要关心的连接告诉epoll(epoll会帮你维护)
        _pepoller->EpollCtl(EPOLL_CTL_ADD, newsocket, EPOLLIN);
    }
    cout << "get a new link  client_ip : "  << client_ip << "  client_port: "<<  client_port << endl;
}

void EpollServer::ParseData(int fd)
{
    //我们不一定能保证读取的数据保证--协议定制--需要处理 
    char buffer[1024];
    ssize_t n =  read(fd, buffer, sizeof(buffer) - 1); 
    if(n > 0)
    {
        buffer[n] = 0;
        cout << "get a message: " << buffer <<endl;

        //构建响应
        std::string  resp = buffer;
        write(fd, resp.c_str(), resp.size());
    }
    else if(n == 0)
    {
        cout << "client quit, fd is " << fd << endl;
        _pepoller->EpollCtl(EPOLL_CTL_DEL, fd, 0); //3.对端连接关闭了, 告诉epoll不再关心这个fd(让底层红黑树删掉这个fd)
        close(fd);//先移除再关闭, 否则先关了, epoll检测fd非法
    }
    else
    {
        cout << "read error " << fd << endl;
        close(fd);
    }
}


